package com.owen.common.utils;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.SecureRandom;
import java.util.Base64;

/**
 * AES加解密工具类
 * 支持ECB和CBC两种模式，PKCS5Padding填充
 */
public class AESUtil {

    // 默认密钥长度
    private static final int KEY_SIZE = 128;

    // 默认加密算法
    private static final String KEY_ALGORITHM = "AES";

    // 默认加密模式和填充方式
    private static final String DEFAULT_CIPHER_ALGORITHM = "AES/ECB/PKCS5Padding";
    private static final String CBC_CIPHER_ALGORITHM = "AES/CBC/PKCS5Padding";

    /**
     * 生成AES密钥
     *
     * @return Base64编码的AES密钥
     */
    public static String generateKeyAsBase64() throws Exception {
        KeyGenerator keyGenerator = KeyGenerator.getInstance(KEY_ALGORITHM);
        keyGenerator.init(KEY_SIZE, new SecureRandom());
        SecretKey secretKey = keyGenerator.generateKey();
        return Base64.getEncoder().encodeToString(secretKey.getEncoded());
    }

    /**
     * 使用ECB模式加密
     *
     * @param content 待加密内容，字符串
     * @param key     Base64编码的密钥
     * @return Base64编码的加密结果
     */
    public static String encryptECB(String content, String key) throws Exception {
        byte[] keyBytes = Base64.getDecoder().decode(key);
        SecretKeySpec secretKeySpec = new SecretKeySpec(keyBytes, KEY_ALGORITHM);

        Cipher cipher = Cipher.getInstance(DEFAULT_CIPHER_ALGORITHM);
        cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec);
        byte[] encryptedBytes = cipher.doFinal(content.getBytes(StandardCharsets.UTF_8));

        return Base64.getEncoder().encodeToString(encryptedBytes);
    }

    /**
     * 使用ECB模式解密
     *
     * @param encryptedContent Base64编码的加密内容
     * @param key              Base64编码的密钥
     * @return 解密后的字符串
     */
    public static String decryptECB(String encryptedContent, String key) throws Exception {
        byte[] keyBytes = Base64.getDecoder().decode(key);
        SecretKeySpec secretKeySpec = new SecretKeySpec(keyBytes, KEY_ALGORITHM);

        Cipher cipher = Cipher.getInstance(DEFAULT_CIPHER_ALGORITHM);
        cipher.init(Cipher.DECRYPT_MODE, secretKeySpec);
        byte[] decryptedBytes = cipher.doFinal(Base64.getDecoder().decode(encryptedContent));

        return new String(decryptedBytes, StandardCharsets.UTF_8);
    }

    /**
     * 生成随机IV向量
     *
     * @return Base64编码的IV向量
     */
    public static String generateIVAsBase64() {
        byte[] iv = new byte[16];
        new SecureRandom().nextBytes(iv);
        return Base64.getEncoder().encodeToString(iv);
    }

    /**
     * 使用CBC模式加密
     *
     * @param content 待加密内容，字符串
     * @param key     Base64编码的密钥
     * @param iv      Base64编码的IV向量
     * @return Base64编码的加密结果
     */
    public static String encryptCBC(String content, String key, String iv) throws Exception {
        byte[] keyBytes = Base64.getDecoder().decode(key);
        byte[] ivBytes = Base64.getDecoder().decode(iv);
        SecretKeySpec secretKeySpec = new SecretKeySpec(keyBytes, KEY_ALGORITHM);
        IvParameterSpec ivParameterSpec = new IvParameterSpec(ivBytes);

        Cipher cipher = Cipher.getInstance(CBC_CIPHER_ALGORITHM);
        cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivParameterSpec);
        byte[] encryptedBytes = cipher.doFinal(content.getBytes(StandardCharsets.UTF_8));

        return Base64.getEncoder().encodeToString(encryptedBytes);
    }

    /**
     * 使用CBC模式解密
     *
     * @param encryptedContent Base64编码的加密内容
     * @param key              Base64编码的密钥
     * @param iv               Base64编码的IV向量
     * @return 解密后的字符串
     */
    public static String decryptCBC(String encryptedContent, String key, String iv) throws Exception {
        byte[] keyBytes = Base64.getDecoder().decode(key);
        byte[] ivBytes = Base64.getDecoder().decode(iv);
        SecretKeySpec secretKeySpec = new SecretKeySpec(keyBytes, KEY_ALGORITHM);
        IvParameterSpec ivParameterSpec = new IvParameterSpec(ivBytes);

        Cipher cipher = Cipher.getInstance(CBC_CIPHER_ALGORITHM);
        cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, ivParameterSpec);
        byte[] decryptedBytes = cipher.doFinal(Base64.getDecoder().decode(encryptedContent));

        return new String(decryptedBytes, StandardCharsets.UTF_8);
    }

    /**
     * 便捷方法：使用默认的ECB模式进行加密
     *
     * @param content  待加密内容
     * @param password 密码，会通过MD5转换为密钥
     * @return 加密后的Base64字符串
     */
    public static String encrypt(String content, String password) throws Exception {
        String key = passwordToKey(password);
        return encryptECB(content, key);
    }

    /**
     * 便捷方法：使用默认的ECB模式进行解密
     *
     * @param encryptedContent 已加密的Base64字符串
     * @param password         密码，会通过MD5转换为密钥
     * @return 解密后的内容
     */
    public static String decrypt(String encryptedContent, String password) throws Exception {
        String key = passwordToKey(password);
        return decryptECB(encryptedContent, key);
    }


    /**
     * 将密码转换为AES可用的密钥（适合从字符串密码生成固定密钥）
     *
     * @param password 密码
     * @return Base64编码的密钥
     */
    private static String passwordToKey(String password) throws Exception {
        KeyGenerator keyGenerator = KeyGenerator.getInstance(KEY_ALGORITHM);
        // 使用密码的哈希值作为随机数种子，确保同样密码产生相同密钥
        SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG");
        secureRandom.setSeed(password.getBytes());
        keyGenerator.init(KEY_SIZE, secureRandom);
        SecretKey secretKey = keyGenerator.generateKey();
        return Base64.getEncoder().encodeToString(secretKey.getEncoded());
    }

}
